--module Src.Main  where
module Main  where

import System
import System.Console.GetOpt
import System.IO.Unsafe
import System.IO
--import System.IO.hPutStr 
--import System.IO.stderr

import Prelude hiding (catch)
import qualified Control.Exception as E

import HaCWB.Parser.Parser
import HaCWB.Parser.Lexer
import HaCWB.Lib.Data
import HaCWB.Lib.Util
import HaCWB.Lib.EvaluateOneStep

{-
  OBJECTIVO: um programa que mostre a evolução de um determinado processo.
  SOLUÇÃO:   selecciona o processo inicial e vai evoluindo passo a passo.
-}

options :: [OptDescr String]
options = [ Option ['h','H']
                   ["help"]
                   (NoArg "H")
                   "output a brief help message"
          , Option ['T','t']
                   ["type"]
                   (ReqArg ('t':) "typeEval")
                   "Type of evaluation (ccs/pi)"
          , Option ['P','p']
                   ["process"]
                   (ReqArg ('p':) "procName")
                   "Process Name"
          ]

main = 
    do args <- getArgs
       let (o,n,errs) = getOpt Permute options args
       let opt  = map (take 1) o
       let arg  = map (drop 1) o
       let opts = zip opt arg
       let errs' = takeUnrecOpts errs
       if ((errs /= []) || ("H" `elem` opt))
         then showErrs errs' options
         else processOptions opt opts (head(n))
    where 
      takeUnrecOpts [] = []
      takeUnrecOpts (x:xs) = let x' = drop 22 x
                             in (take 1 x') : takeUnrecOpts xs


--------------------------------------------------------------------------------
--	Se houver erros na chamada da ferramenta, eles são colocados um por 
--	linha, seguidos do menú de ajuda.
--------------------------------------------------------------------------------

showErrs [] opts = do showErrs' [] opts
showErrs l opts = do putStr "\nUnrecognized options: "
                     showErrs' l opts


showErrs' [] opts = putStr ((usageInfo usageheader opts) ++ 
               "\n\nFor more information see README file.\n\n")
  where
    usageheader = "\n\nHaCWB - A Haskell tool to view evolution of processes.\n" ++ 
                  "Usage: hacwb options ... \n\nList of options:\n"
showErrs' [x] opts = do putStr x
                        showErrs' [] opts
showErrs' (x:xs) opts = do putStr (x ++ ", ")
                           showErrs' xs opts

{--------------------------------------------------------------------------------
  ---  Processamento da lista de opções introduzida pelo utilizador.
  * -h - help
  * -t - evaluation type
  * -p - process name to initiate evaluation
--------------------------------------------------------------------------------}


processOptions :: [String]            --Options list
               -> [(String,String)]   --Pair of option - argument
               -> String              -- File to read
               -> IO()
processOptions opts l file = 
                        let type_eval = if("t" `elem` opts)
                                        then let t = snd((head . filter ((=="t") . fst)) l)
                                             in if(t `elem` ["pi", "ccs"])
                                                then t
                                                else "pi"
                                        else "pi"
                        in case("p" `elem` opts) of 
                             False -> putStr("Process name missing.\n")
                             True  -> let nameP = snd((head . filter ((=="p") . fst)) l)
                                      in initialize nameP type_eval file --"inputs/in4"
--    where
initialize nameP typeEval file = 
                    do let cts = readFile file
                           str = unsafePerformIO cts
                           lst = buildLst str
                       putStrLn("eval type: " ++ typeEval ++ "\n"++ 
                                "input file: " ++ file ++ "\n" ++
                                "process name: " ++ nameP )
                       case (lookup nameP lst) of 
                             Nothing  -> error("Process name is incorrect.")  
                             (Just a) -> evaluate a typeEval lst

buildLst s = 
            let lst = parse s
            in case lst of 
              (Left a)  -> error(a++"\n")
              (Right b) -> b

{-
  teste = evaluate p1 "pi" lst1
  p1 = (Var "a" `Dot` Zero)
  p2 = (Var "b" `Dot` Zero)
  lst1 = [("A",p1),("B", p2)]
-}
evaluate proc typeEval lst = 
        do let opts = if typeEval == "pi"
                        then eval1stepPi lst proc
                        else eval1stepccs lst proc
           putStr("\n\t\t"++show(proc)++"\n\n")
           putStr(showProcesses opts)
           line <- getLine
           E.catch (
               do let name = read line::Int
                  if not((name <= length(opts)) && (name >= 0))
                     then do putStrLn "wrong option."
                             evaluate proc typeEval lst
                     else case name of
                           0 -> do putStrLn "Goodbye"
                           _ -> evaluate (snd(opts !! (name-1))) typeEval lst        
                ) (\err -> do putStrLn "wrong option."
                              evaluate proc typeEval lst )

showProcesses lst = showProcessesAux 1 lst

showProcessesAux _ []     = "\n0: Exit\n"
showProcessesAux n (h:t)  = (show n) ++ ": " ++ 
                            (show (fst h)) ++ " -> " ++
                            (show (snd h)) ++ "\n" ++
                            (showProcessesAux (n+1) t)
                        